import { observable, action, runInAction, useStrict, autorun, computed, reaction, comparer, flow } from 'mobx';


// comparer.identity: 使用恒等 (===) 运算符来判定两个值是否相同。
// comparer.default: 等同于 comparer.identity，但还认为 NaN 等于 NaN 。
// comparer.structural: 执行深层结构比较以确定两个值是否相同。
// console.log(comparer.structural({ name: "1" }, { name: "01" })) //false

const map = observable.map({ key: "value" });
map.set("key", "new value");

const list = observable([1, 2, 4]);
list[2] = 3;

const person = observable({
  firstName: "一缕清风",
  lastName: "Ken"
});
person.firstName = "肯古巴";

const temperature = observable.box(20);
autorun(() => {
  console.log(temperature.get(), "temperature.get()")
}, {
  delay: 300,
  name: "字符串，用于在例如像 spy 这样事件中用作此 reaction 的名称",
  onError(e) { window.console.log("Please enter a valid age") }
});
temperature.observe(function () {
  console.log("———— 触发了 observable.box(xxxx).observe() ———— ");
})
temperature.set(25);




const todos = observable([
  { name: "Ken", done: true, },
  { name: "一缕清风", done: false }
]);

// reaction 的错误用法: 对 length 的变化作出反应, 而不是 name 的变化!
const reaction1 = reaction(
  () => todos.length,
  length => console.log("reaction1:", todos.map(todo => todo.name).join(", ")),
  {
    // fireImmediately: true,
    // fireImmediately: 布尔值，用来标识效果函数是否在数据函数第一次运行后立即触发。默认值是 false 。
    // delay: 可用于对效果函数进行去抖动的数字(以毫秒为单位) 。如果是 0(默认值) 的话，那么不会进行去抖。
    // equals: 默认值是 comparer.default 。如果指定的话，这个比较器函数被用来比较由 数据 函数产生的前一个值和后一个值。只有比较器函数返回 false 效果 函数才会被调用。此选项如果指定的话，会覆盖 compareStructural 选项。
    // name: 字符串，用于在例如像 spy 这样事件中用作此 reaction 的名称。
    // onError: 用来处理 reaction 的错误，而不是传播它们。
    // scheduler: 设置自定义调度器以决定如何调度 autorun 函数的重新运行
  }
);
// reaction 的正确用法: 对 length 和 name 的变化作出反应
const reaction2 = reaction(
  () => todos.map(todo => todo.name),
  (names, reaction) => {
    console.log("reaction2:", names.join(", "));
    reaction.dispose();
  }
);
const reaction3 = computed(() => {
  console.log("语法糖根源 -> computed(expression).observe(action(sideEffect))")
  return todos.map(todo => todo.name)
}).observe(action(({ newValue, oldValue }) => {
  console.log(newValue, oldValue, "reaction3打印输出")
  console.log("reaction3:语法糖的真相 ____________________");
}))
const reaction4 = autorun(() =>
  action((newValue) => {
    console.log(newValue, "reaction4打印输出")
    console.log("reaction4:语法糖的真相 --------------------")
  })
    (todos.map(todo => todo.name))
)
// autorun 对它函数中使用的任何东西作出反应
const autorun1 = autorun(
  () => console.log("autorun1:", todos.map(todo => todo.name).join(", "))
);

// todos.push({ name: "肯古巴", done: false });
todos[0].name = "Ke"
todos[0].name = "K"



// useStrict(ture)
class HomeStore {
  constructor() {
    // 监控数据变化的回调,读取什么参数，即代表将要监控什么数据
    autorun(() => {
      console.log(`this.currentNumber在autorun中 已被修改为 ${this.currentNumber}`);
    });
  }

  @observable state = {}
  @observable flowState = "pending"
  @observable currentNumber = 0;

  @computed get total() {
    return `${this.currentNumber * 10}`;
  }
  set total(value) { // 这是一个自动的动作，不需要注解
    this.currentNumber = value;
  }

  @action // 'this' 永远都是正确的
  async setCurrentNumber(symbol = "+") {
    switch (symbol) {
      case "+":
        this.currentNumber += 1;
        break;
      case "-":
        if (this.currentNumber < 1) return;
        this.currentNumber -= 1;
        break;
    }
  }

  @action.bound
  async setCurrentNumberAsync(symbol = "+") {
    // 设置到状态机 - 如果是异步，必须在runInAction
    runInAction(() => {
      switch (symbol) {
        case "+":
          this.currentNumber += 1;
          break;
        case "-":
          if (this.currentNumber < 1) return;
          this.currentNumber -= 1;
          break;
      }
    })
  }


  // fetchProjects = flow(function* () { // <- 注意*号，这是生成器函数！
  //   this.githubProjects = []
  //   this.state = "pending"
  //   try {
  //     const projects = yield fetchGithubProjectsSomehow() // 用 yield 代替 await
  //     const filteredProjects = somePreprocessing(projects)
  //     // 异步代码块会被自动包装成动作并修改状态
  //     this.state = "done"
  //     this.githubProjects = filteredProjects
  //   } catch (error) {
  //     this.state = "error"
  //   }
  // })
}
export default new HomeStore();
